package com.dream.app.controller;

import java.util.Enumeration;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.dream.app.cache.AppGroupCache;
import com.dream.app.cache.AppGroupResourceCache;
import com.dream.app.cache.AppOrgCache;
import com.dream.app.cache.AppPositionCache;
import com.dream.app.cache.AppResourceCache;
import com.dream.app.cache.AppUserResourceCache;
import com.dream.app.service.AppPositionService;
import com.dream.app.service.AppService;
import com.dream.app.service.OrgService;
import com.dream.app.service.UserService;
import com.dream.base.controller.BaseController;
import com.dream.base.web.job.InitialDatabaseService;
import com.dream.model.app.AppAbstractUser;
import com.dream.model.app.AppAbstractUser.UserStatus;
import com.dream.model.app.AppGroup;
import com.dream.model.app.AppImage;
import com.dream.model.app.AppPosition;
import com.dream.model.app.AppUser;
import com.dream.utils.annotation.AccessLog;
import com.dream.utils.annotation.AccessToken;
import com.dream.utils.annotation.AccessTokenType;
import com.dream.utils.annotation.SkipAuthority;
import com.dream.utils.cookie.CookieUtils;
import com.dream.utils.hibernate.PagingVO;
import com.dream.utils.log.DreamLogUtils;
import com.dream.utils.random.validate.RandomValidateCodeUtils;
import com.dream.utils.system.cfg.SystemConfigUtils;
import com.dream.vo.app.AppCodeVO;
import com.dream.vo.app.GroupVO;
import com.dream.vo.app.PositionVO;
import com.dream.vo.app.UserVO;
import com.dream.vo.base.Constants;
import com.dream.vo.base.FirstGroup;
import com.dream.vo.base.FourthGroup;
import com.dream.vo.base.MvcValidtorResult;
import com.dream.vo.base.ResultType;
import com.dream.vo.base.SecondGroup;
import com.google.common.collect.Maps;

/**
 * @copyright evan
 * @author evan
 * @Revision
 * @date 2013/9/29
 */
@Controller
@RequestMapping(value = "/app")
public class AppController extends BaseController{
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private AppResourceCache appResourceCache;
	
	@Autowired
	private AppOrgCache appOrgCache;
	
	@Autowired
	private AppGroupCache appGroupCache;
	
	@Autowired
	private AppGroupResourceCache appGroupResourceCache;
	
	@Autowired
	private AppPositionCache appPositionCache;
	
	@Autowired
	private AppUserResourceCache appUserResourceCache;
	
	
	@Autowired
	private AppPositionService appPositionService;
	
	@Autowired
	private AppService appService;
	
	@Autowired
	private OrgService orgService;
	
	private void refreshAllCache(AppUser u){
		appResourceCache.reload();
		appOrgCache.reload();
		appGroupCache.reload();
		appGroupResourceCache.refresh();
		appPositionCache.reload();
		appUserResourceCache.reload(u);
	}
	
	@Autowired
	private InitialDatabaseService initialDatabaseService;
	
	@PostConstruct
	public void initData(){
		initialDatabaseService.init();
	}
	
	
	@ResponseBody
	@RequestMapping(value = "/login")
	@AccessLog(module="app",content="用户登录")
	@SkipAuthority
	public Map<String, Object> login(Model modelMap,@Validated({FirstGroup.class}) UserVO userVO,BindingResult valResult,HttpServletResponse response) {
		
		Map<String,Object> result = Maps.newHashMap();

		MvcValidtorResult errors = populateErrors(valResult);
		
		if(valResult.hasErrors()){
			result.put(RESULT_TYPE, ResultType.INPUT.toInteger());
			result.put(RESULT_CONTENT, errors);
			
		}else{
			AppUser user = null;
			int lockCount = SystemConfigUtils.instance().getInteger("login.lock.count", 6);
			int unlockMins = SystemConfigUtils.instance().getInteger("login.unlock.minitue", 10);
			boolean lockFalg = SystemConfigUtils.instance().getBoolean("login.lock.flag");
			try{
				 
				 Boolean isLocked = false;
				 if(lockFalg){
					 isLocked = userService.isLockedUser(userVO, lockCount, unlockMins);
				 }
				 
				 if(isLocked == null){
					 result.put(RESULT_TYPE,ResultType.INPUT.toInteger());
					 addFieldMessage(errors, "id", "err0009");
					 result.put(RESULT_CONTENT, errors);
				 }else if(isLocked){
					 result.put(RESULT_TYPE,ResultType.INPUT.toInteger());
					 addFieldMessage(errors,"id", "err0021",new String[]{Integer.toString(lockCount),Integer.toString(unlockMins)});
					 result.put(RESULT_CONTENT, errors);
				 }else{
						user = userService.login(userVO);
						//email or password is wrong
						if(user==null ){
							result.put(RESULT_TYPE,ResultType.INPUT.toInteger());
							addFieldMessage(errors, "id", "err0009");
							result.put(RESULT_CONTENT, errors);
						}else{
							//pass the validation
							result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger()); 
							saveUser(user,userVO.getRememberMe(),getRequest(),response);
							
							 // TODO refresh cache
							refreshAllCache(user);
							
						}
				 }
			}catch(Exception ex){
				result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
				DreamLogUtils.error(this,"login","login occured exception", ex);
			}
		}
		return result;
	}
	
	@ResponseBody
	@RequestMapping(value = "/user/add")
	@AccessLog(module="app",content="新增用戶")
	@AccessToken(AccessTokenType.verify)
	public Map<String, Object> userAdd(@Validated({FirstGroup.class,SecondGroup.class}) UserVO userVO,BindingResult valResult) {
		
		Map<String,Object> result = Maps.newHashMap();
		MvcValidtorResult errors = populateErrors(valResult);

		if(valResult.hasErrors()){
			result.put(RESULT_TYPE, ResultType.INPUT.toInteger());
			result.put(RESULT_CONTENT, errors);
			
		}else{
			try{
				if(userService.isExistedUser(userVO.getId())){
					
					addFieldMessage(errors, "id", "err0004");
					result.put(RESULT_TYPE, ResultType.INPUT.toInteger());

				}else{
					userService.addNew(userVO,getUser());
					result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
				}
				
			}catch(Exception ex){
				result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
				DreamLogUtils.error(this,"userAdd","add user occured exception", ex);
			}
		}
		return result;
	}
	

	@ResponseBody
	@RequestMapping(value = "/user/modify")
	@AccessLog(module="app",content="修改用戶")
	@AccessToken(AccessTokenType.verify)
	public Map<String, Object> userModfiy(@Validated({SecondGroup.class}) UserVO userVO,BindingResult valResult) {
		
		Map<String,Object> result = Maps.newHashMap();
		MvcValidtorResult errors = populateErrors(valResult);
		
		if(valResult.hasErrors()){
			result.put(RESULT_TYPE, ResultType.INPUT.toInteger());
			result.put(RESULT_CONTENT, errors);
		}else{
			try{
				userService.modifyUser(userVO,getUser());
				result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
			}catch(Exception ex){
				result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
				DreamLogUtils.error(this,"userModfiy","modify user occured exception", ex);
			}
		}
		return result;
	}
	
	@ResponseBody
	@RequestMapping(value = "/user/exist/{userId}")
	@AccessLog(module="app",content="用户存在性检查")
	public Boolean userExist(@PathVariable String userId) {
		return userService.isExistedUser(userId);
	}
	
	@ResponseBody
	@RequestMapping(value = "/user/logout")
	@AccessLog(module="app",content="用户注销")
	@SkipAuthority
	public void logout(HttpServletResponse response) {
		
		HttpSession session = getRequest().getSession(true);
		try{
			 session = getRequest().getSession(true);
			if (session != null){
				ACTIVE_SESSION.remove(session.getId());
				session.removeAttribute(Constants.USER_ID);
				session.invalidate();
				
			}
			response.sendRedirect(getLoginUri());
		}catch(Exception e){
			DreamLogUtils.error(this, "logout", "logout exception", e);
		}
		
	}
	
	/**
	 * 
	 * @copyright evan
	 * @author evan
	 * @date 2013-9-3
	 * @param user
	 * @param rememberMe
	 * @param request
	 * @param response
	 */
	private void saveUser(AppUser user,String rememberMe,HttpServletRequest request,HttpServletResponse response){
		
		//session fixable
		HttpSession session = request.getSession();
		Map<String,Object> map = Maps.newHashMap();
		
		if(session == null){
			return ;
		}
		for(Enumeration<?> enumer = session.getAttributeNames();enumer.hasMoreElements();){
			String key = (String)enumer.nextElement();
			map.put(key, session.getAttribute(key));
		}
		session.invalidate();
		map.remove(RandomValidateCodeUtils.RANDOM_IMAGE_VALIDATE);
		session = request.getSession(true);
		for(Map.Entry<String, Object> entry : map.entrySet()){
			session.setAttribute(entry.getKey(), entry.getValue());
		}
		session.setAttribute(Constants.USER_ID, user);
		ACTIVE_SESSION.put(session.getId(), session);
		
		//save user id to cookie
		if("on".equals(rememberMe)){
			CookieUtils.addCookie(response, request, Constants.USER_ID, user.getId());
		}else{
			CookieUtils.removeCookie(response, request, Constants.USER_ID);
		}
	}
	
	/**
	 * 
	 * @copyright evan
	 * @author evan
	 * @date 2013-9-3
	 * @param vo
	 * @param httpRequest
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value="/image/upload",produces = {"text/html;charset=UTF-8"})
	@AccessLog(module="app",content="用户图片上传")
	@SkipAuthority
	public String  uploadUserIamge(UserVO vo,HttpServletRequest httpRequest){
		
		Map<String,Object> result = Maps.newHashMap();
		try {
			
			AppImage image = userService.uploadUserIamge(getUser(), vo, httpRequest);
			if(image != null){
				result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
				result.put(RESULT_CONTENT, image);
			}else{
				result.put(RESULT_TYPE,ResultType.ERROR.toInteger());
			}
		} catch (Exception e) {
			result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
			DreamLogUtils.error(this, "uploadUserIamge", "upload image occured exception", e);
		}
		
		return JSONObject.fromObject(result).toString();
	}
	
	/**
	 * 
	 * @param userId
	 * @param modelMap
	 * @return
	 */
	@RequestMapping(value="/user/setting/{userId}")
	@AccessLog(module="app",content="账户设置")
	@AccessToken(AccessTokenType.generate)
	@SkipAuthority
	public String  userSetting(@PathVariable String userId, Model modelMap){
		
		// 获取最新值
		AppAbstractUser user = getUser();
		modelMap.addAttribute("user", user);
		return "user_setting";
	}
	
	/**
	 * 
	 * @copyright evan
	 * @author evan
	 * @date 2013-9-3
	 * @param userId
	 * @param modify
	 * @param modelMap
	 * @return
	 */
	@RequestMapping(value="/user/detail/{userId}/{modify}")
	@AccessLog(module="app",content="用戶详细")
	@AccessToken(AccessTokenType.generate)
	public String  userDetail(@PathVariable String userId,@PathVariable Boolean modify,Model modelMap){
		
		AppUser user = userService.getDetail(userId);
		modelMap.addAttribute("firstOrgs",orgService.getFirstOrg());
		modelMap.addAttribute("user", user);
		
		return modify?"user_add_mod":"user_detail";
	}
	
	@RequestMapping(value="/user/init")
	@AccessLog(module="app",content="用戶详细")
	@AccessToken(AccessTokenType.generate)
	@SkipAuthority
	public String  userInit(Model modelMap){
		
		modelMap.addAttribute("firstOrgs",orgService.getFirstOrg());
		
		return "user_add_mod";
	}
	
	
	/**
	 * 
	 * @copyright evan
	 * @author Bright
	 * @date 2013-9-9
	 * @param modelMap
	 * @param userVO
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/user/setting/modify")
	@AccessLog(module="app",content="账户设置")
	@AccessToken(AccessTokenType.verify)
	@SkipAuthority
	public Map<String, Object> userModfiySetting(@Validated({SecondGroup.class}) UserVO userVO,BindingResult valResult) {
		
			MvcValidtorResult errors = populateErrors(valResult);
			Map<String, Object> result = Maps.newHashMap();	
			if(valResult.hasErrors()){
				result.put(RESULT_TYPE, ResultType.INPUT.toInteger());
				result.put(RESULT_CONTENT, errors);
			}else{
				try{
					userService.modifyUserSetting(userVO);
					result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
					
					// 更新后账户信息保存session中
					HttpServletRequest httpRequest =  getRequest();
					HttpSession session = httpRequest.getSession(false);
					AppAbstractUser user = userService.getDetail(userVO.getId());
					session.setAttribute(Constants.USER_ID, user);
					
				}catch(Exception ex){
					result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
					DreamLogUtils.error(this,"userModfiySetting","modify user occured exception", ex);
				}
			}
		return result;
	}
	
	/**
	 * 
	 * @copyright evan
	 * @author Bright
	 * @date 2013-9-9
	 * @param modelMap
	 * @param userVO
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value = "/user/modify/password")
	@AccessLog(module="app",content="密码修改")
	@AccessToken(AccessTokenType.verify)
	@SkipAuthority
	public Map<String, Object> userModfiyPassword(@Validated({FourthGroup.class}) UserVO userVO,BindingResult valResult) {
		
		MvcValidtorResult errors = populateErrors(valResult);
		Map<String, Object> result = Maps.newHashMap();	
		
		userVO.setId(this.getUser().getId());
		String sureMsg = userVO.validateSurePwd();
		if(StringUtils.isNotBlank(sureMsg)){
			this.addFieldMessage(errors, "surePassword", sureMsg);
		}
		if(errors.hasErrors()){
			result.put(RESULT_TYPE, ResultType.INPUT.toInteger());
			result.put(RESULT_CONTENT, errors);
		}else{
			try{
				if(userService.findPwd(userVO)) {
					// 输入原密码正确，更新密码
					userService.changePwd(userVO);
					result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
				} else {
					
					this.addFieldMessage(errors, "password", "err0018");
					result.put(RESULT_TYPE,ResultType.INPUT.toInteger());
					result.put(RESULT_CONTENT, errors);
				}
					
			}catch(Exception ex){
					result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
					DreamLogUtils.error(this,"userModfiySetting","modify user occured exception", ex);
			}
		}
			
		return result;
	}
	@ResponseBody
	@RequestMapping(value = "/user/resource/modify")
	@AccessLog(module="app",content="修改用戶权限")
	@AccessToken(AccessTokenType.verify)
	public Map<String, Object> userResourceModfiy(Model modelMap,GroupVO vo) {
		
		Map<String,Object>  result = Maps.newHashMap();
		try{
			userService.modifyUserResource(vo, getUser());
			result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
		}catch(Exception ex){
			result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
			DreamLogUtils.error(this,"userModfiy","modify user occured exception", ex);
		}
		return result;
	}
	
	/**
	 * 
	 * @author evan
	 * @Revision
	 * @date 2013-9-9
	 * @param userId
	 * @param modelMap
	 * @return
	 */
	@RequestMapping(value="/user/resource/detail/{userId}")
	@AccessLog(module="app",content="用戶权限详细")
	@AccessToken(AccessTokenType.generate)
	@SkipAuthority
	public String  userResourceDetail(@PathVariable String userId,Model modelMap){
		
		modelMap.addAttribute("myResources", userService.getMyResources(userId));
		modelMap.addAttribute("userId", userId);
		modelMap.addAttribute("resources",appResourceCache.getAllByModule());
		return "user_resource_detail";
	}
	
	
	@RequestMapping(value = "/user/query")
	@AccessLog(module="app",content="查询用戶")
	public String userQuery(Model modelMap,UserVO userVO,PagingVO pageVO) {
	
		modelMap.addAttribute("pageVO", userService.queryUser(userVO, pageVO));
		return "app/user/data/user_list_data";
	}
	
	@RequestMapping(value = "/user/query/pop")
	@AccessLog(module="app",content="查询用戶")
	@SkipAuthority
	public String userQueryPop(Model modelMap,UserVO userVO,PagingVO pageVO) {
	
		userVO.setUserStatus(UserStatus.activeList);
		modelMap.addAttribute("pageVO", userService.queryUser(userVO, pageVO));
		return "app/common/data/user_list_data";
	}
	
	@ResponseBody
	@RequestMapping(value = "/user/delete/{userId}")
	@AccessLog(module="app",content="删除用戶")
	public  Map<String, Object> userDelete(@PathVariable String userId) {
		
		Map<String,Object> result = Maps.newHashMap();
		try {
			userService.delUser(userId, getUser());
			result.put(RESULT_TYPE, ResultType.SUCCESS.toInteger());
		} catch (Exception ex) {
			result.put(RESULT_TYPE,ResultType.ERROR.toInteger());
			DreamLogUtils.error(this, "userDelete","delete user occured exception", ex);
		}
		return result;
	}
	
	@RequestMapping(value = "/code/list")
	@AccessLog(module="app",content="系统参数")
	@SkipAuthority
	public String appCodeQuery(Model modelMap,AppCodeVO vo,PagingVO pageVO) {
	
		modelMap.addAttribute("pageVO", appService.queryAppCode(vo, pageVO));
		return "app/app_code/data/code_list_data";
	}
	
	@RequestMapping(value = "/code/item/list")
	@AccessLog(module="app",content="系统参数详细")
	@SkipAuthority
	public String appCodeItemQuery(Model modelMap,AppCodeVO vo,PagingVO pageVO) {
		
		pageVO.setPageSize("100");
		modelMap.addAttribute("pageVO", appService.queryAppCodeItem(vo, pageVO));
		return "app/app_code/data/code_item_list_data";
	}
	
	@ResponseBody
	@RequestMapping(value = "/code/item/update")
	@AccessLog(module="app",content="系统参数更新")
	@SkipAuthority
	public Map<String,Object> appCodeItemUpdate(Model modelMap,@Validated({FirstGroup.class}) AppCodeVO vo,BindingResult valResult,PagingVO pageVO) {
		
		MvcValidtorResult errors = populateErrors(valResult);
		Map<String, Object> result = Maps.newHashMap();	
		if(errors.hasErrors()){
			result.put(RESULT_TYPE, ResultType.INPUT.toInteger());
			result.put(RESULT_CONTENT, errors);
		}else{
			try{
				appService.updateAppCodeItem(vo, getUser());
				result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
			}catch(Exception ex){
					result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
					DreamLogUtils.error(this,"appCodeItemUpdate","modify app code occured exception", ex);
			}
		}
			
		return result;
	}
	
	@ResponseBody
	@RequestMapping(value = "/code/item/delete/{id}")
	@AccessLog(module="app",content="删除用戶")
	@SkipAuthority
	public  Map<String, Object> codeItemDelete(@PathVariable long id) {
		
		Map<String,Object> result = Maps.newHashMap();
		try {
			appService.deleteAppCodeItem(id, getUser());
			result.put(RESULT_TYPE, ResultType.SUCCESS.toInteger());
		} catch (Exception ex) {
			result.put(RESULT_TYPE,ResultType.ERROR.toInteger());
			DreamLogUtils.error(this, "codeItemDelete","delete code item occured exception", ex);
		}
		return result;
	}
	
	
	@RequestMapping(value = "/position/list")
	@AccessLog(module="app",content="职位列表")
	@SkipAuthority
	public String positionQuery(Model modelMap) {
		
		modelMap.addAttribute("list", appPositionService.list());
		return "app/position/data/position_list_data";
	}
	
	@ResponseBody
	@RequestMapping(value = "/position/update")
	@AccessLog(module="app",content="职位更新")
	@SkipAuthority
	public Map<String,Object> positionUpdate(Model modelMap,PositionVO vo) {
		
		Map<String, Object> result = Maps.newHashMap();	
		try{
			appPositionService.addNew(vo, getUser());
			result.put(RESULT_TYPE,ResultType.SUCCESS.toInteger());
		}catch(Exception ex){
			result.put(RESULT_TYPE, ResultType.EXCEPTION.toInteger());
			DreamLogUtils.error(this,"positionUpdate","modify position code occured exception", ex);
		}
			
		return result;
	}
	
	@ResponseBody
	@RequestMapping(value = "/position/delete/{id}")
	@AccessLog(module="app",content="删除职位")
	@SkipAuthority
	public  Map<String, Object> positionDelete(@PathVariable Long id) {
		
		Map<String,Object> result = Maps.newHashMap();
		try {
			appPositionService.delete(id, getUser());
			result.put(RESULT_TYPE, ResultType.SUCCESS.toInteger());
		} catch (Exception ex) {
			result.put(RESULT_TYPE,ResultType.ERROR.toInteger());
			DreamLogUtils.error(this, "positionDelete","delete position item occured exception", ex);
		}
		return result;
	}
	
	@ModelAttribute("positions")
	public Map<Long,AppPosition> getAllPosition(){
		
		return appPositionCache.getAll();
	}
	
	@ModelAttribute("groups")
	public Map<String,AppGroup> getAllGroup(){
		
		return appGroupCache.getAll();
	}
	
	
}
